home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #5 / Amiga Plus CD - 2000 - No. 5.iso / Tools / Musik / Misc / Amster / Source / transfer.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-01  |  11.4 KB  |  494 lines

  1. /*
  2. ** Amster - Transfer
  3. ** by Jacob Laursen <laursen@myself.com>
  4. */
  5.  
  6. #include "include/config.h"
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10.  
  11. #include <proto/dos.h>
  12. #include <proto/exec.h>
  13. #include <proto/socket.h>
  14.  
  15. #include <netdb.h>
  16. #include <sys/time.h>
  17. #include <sys/socket.h>
  18. #include <sys/ioctl.h>
  19. #include <netinet/tcp.h>
  20. #include <bsdsocket/socketbasetags.h>
  21. #include <error.h>
  22. #include <time.h>
  23.  
  24. #include "include/mui.h"
  25. #include <MUI/NListview_mcc.h>
  26. #include "include/download.h"
  27. #include "include/upload.h"
  28. #include "include/gui.h"
  29. #include "include/panel.h"
  30. #include "include/prefs.h"
  31. #include "include/transfer.h"
  32. #include "amster_Cat.h"
  33. #include "include/protos.h"
  34.  
  35.  
  36. MUIF translistdisp(REG(a2) char **array, REG(a1) songtrans sd)
  37. {
  38.     static char bufd2[50], bufd3[50], bufd4[50], bufd5[50];
  39.     static char bufu2[50], bufu3[50], bufu4[50], bufu5[50];
  40.     char *buf2, *buf3, *buf4, *buf5;
  41.  
  42.     static char *states[] = {
  43.         (char *)_MSG_TRANS_STAT_PREPARE,
  44.         (char *)_MSG_TRANS_STAT_QUEUE,
  45.         (char *)_MSG_TRANS_STAT_WAIT,
  46.         (char *)_MSG_TRANS_STAT_CONN,
  47.         (char *)_MSG_TRANS_STAT_REQ,
  48.         (char *)_MSG_TRANS_STAT_INIT,
  49.         (char *)_MSG_TRANS_STAT_DL,
  50.         (char *)_MSG_TRANS_STAT_UL,
  51.         (char *)_MSG_TRANS_STAT_FIN,
  52.         (char *)_MSG_TRANS_STAT_ABORT,
  53.         (char *)_MSG_TRANS_STAT_ERROR,
  54.         NULL
  55.     };
  56.  
  57.     static char *errors[] = {
  58.         (char *)_MSG_TRANS_STAT_ERROR,
  59.         (char *)_MSG_TRANS_ERROR_FILEOPEN,
  60.         (char *)_MSG_TRANS_ERROR_FILEREAD,
  61.         (char *)_MSG_TRANS_ERROR_FILEWRITE,
  62.         (char *)_MSG_TRANS_ERROR_NET_UNKNOWN,
  63.         (char *)_MSG_TRANS_ERROR_LOGGEDOUT,
  64.         (char *)_MSG_TRANS_ERROR_NOTFOUND,
  65.         (char *)_MSG_TRANS_ERROR_INVALIDREQUEST,
  66.         (char *)_MSG_TRANS_ERROR_TEASER,
  67.         (char *)_MSG_TRANS_ERROR_BUSY,
  68.         (char *)_MSG_TRANS_ERROR_NOTREQ,
  69.         (char *)_MSG_TRANS_ERROR_NET_TIMEOUT,
  70.         NULL
  71.     };
  72.  
  73.     static char *NetError[] = {
  74.         (char *)_MSG_TRANS_ERROR_NET_TIMEOUT,
  75.         (char *)_MSG_TRANS_ERROR_NET_REFUSED,
  76.         (char *)_MSG_TRANS_ERROR_NET_RESET,
  77.         (char *)_MSG_TRANS_ERROR_NET_PIPE,
  78.         NULL
  79.     };
  80.  
  81.     if (states[0] == (char *)_MSG_TRANS_STAT_PREPARE)
  82.         localize_array(states);
  83.  
  84.     if (errors[0] == (char *)_MSG_TRANS_STAT_ERROR)
  85.         localize_array(errors);
  86.  
  87.     if (NetError[0] == (char *)_MSG_TRANS_ERROR_NET_TIMEOUT)
  88.         localize_array(NetError);
  89.  
  90.     if (sd) {
  91.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  92.             buf2 = bufd2;
  93.             buf3 = bufd3;
  94.             buf4 = bufd4;
  95.             buf5 = bufd5;
  96.         }
  97.         else {
  98.             buf2 = bufu2;
  99.             buf3 = bufu3;
  100.             buf4 = bufu4;
  101.             buf5 = bufu5;
  102.         }
  103.  
  104.         *array++ = nap_strippath(sd->song->title);
  105.  
  106.         if (sd->state == DLS_WAIT) {
  107.             sprintf(buf5, states[sd->state], sd->ErrorCode);
  108.             *array++ = buf5;
  109.         }
  110.         else if (sd->state != DLS_ERROR)
  111.             *array++ = states[sd->state];
  112.         else {
  113.             switch (sd->error) {
  114.                 case ERROR_FILEOPEN:
  115.                 case ERROR_FILEREAD:
  116.                 case ERROR_FILEWRITE:
  117.                     sprintf(buf5, errors[sd->error], sd->ErrorCode);
  118.                     *array++ = buf5;
  119.                     break;
  120.                 case ERROR_NET:
  121.                     switch (sd->ErrorCode) {
  122.                         case ETIMEDOUT:
  123.                             *array++ = NetError[ERROR_NET_TIMEOUT];
  124.                             break;
  125.                         case ECONNREFUSED:
  126.                             *array++ = NetError[ERROR_NET_REFUSED];
  127.                             break;
  128.                         case ECONNRESET:
  129.                             *array++ = NetError[ERROR_NET_RESET];
  130.                             break;
  131.                         case EPIPE:
  132.                             *array++ = NetError[ERROR_NET_PIPE];
  133.                             break;
  134.                         default:
  135.                             sprintf(buf5, errors[sd->error], sd->ErrorCode);
  136.                             *array++ = buf5;
  137.                     }
  138.                     break;
  139.                 default:
  140.                     *array++ = errors[sd->error];
  141.             }
  142.         }
  143.  
  144.         if (sd->size > 0)
  145.             sprintf(buf2,"\33r%ld / %ld (%d%%)", sd->cur, sd->size, (sd->cur*100+5)/sd->size);
  146.         else sprintf(buf2, "\33r0");    /* Can this happen? */
  147.         *array++ = buf2;
  148.  
  149.         if (sd->cps > 0) {
  150.             if (sd->stalltick < 5 || sd->state >= DLS_FIN) {    /* 5 seconds */
  151.                 sprintf(buf3, "%d", sd->cps);
  152.                 *array++ = buf3;
  153.             }
  154.             else {
  155.                 *array++ = (char *)MSG_TRANS_STAT_STALLED;
  156.             }
  157.             sprintf(buf4, "%ld:%02ld / %ld:%02ld", sd->transtime/60, sd->transtime%60, sd->timeleft/60, sd->timeleft%60);
  158.             *array = buf4;
  159.         }
  160.         else {
  161.             *array++ = "-";
  162.             *array   = "-";
  163.         }
  164.  
  165.     }
  166.     else {
  167.         *array++ = (char *)MSG_LH_FILE;
  168.         *array++ = (char *)MSG_LH_STATE;
  169.         *array++ = (char *)MSG_LH_SIZE;
  170.         *array++ = (char *)MSG_LH_CPS;
  171.         *array =   (char *)MSG_LH_ETIME;
  172.     }
  173.     return 0;
  174. }
  175.  
  176.  
  177. MUIF translistdest(REG(a2) APTR pool, REG(a1) songtrans sd)
  178. {
  179.     nap_songfree(sd->song);
  180.     if (sd->fname) free(sd->fname);
  181.     free(sd);
  182.  
  183.     return 0;
  184. }
  185.  
  186.  
  187. ULONG dl_setup(struct IClass *cl, Object *obj, Msg msg)
  188. {
  189.     struct TransferData *data = INST_DATA(cl, obj);
  190.  
  191.     if (!DoSuperMethodA(cl, obj, msg))
  192.         return(FALSE);
  193.  
  194.     DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->ihnode);
  195. /*    DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->watchnode);*/
  196.  
  197.     return(TRUE);
  198. }
  199.  
  200.  
  201. ULONG dl_muicleanup(struct IClass *cl, Object *obj, Msg msg)
  202. {
  203.     struct TransferData *data = INST_DATA(cl,obj);
  204.  
  205.     DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->ihnode);
  206. /*    DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->watchnode);*/
  207.  
  208.     return(DoSuperMethodA(cl,obj,msg));
  209. }
  210.  
  211.  
  212. void CalculateCps(songtrans sd)
  213. {
  214.     if (sd->cur != sd->oldsize) {
  215.         sd->stalltick = 0;
  216.         sd->oldsize = sd->cur;
  217.     }
  218.     else sd->stalltick++;
  219.  
  220.     sd->transtime = time(NULL) - sd->starttime;
  221.     if (sd->transtime == 0) sd->transtime = 1;
  222.     sd->cps = (sd->cur - sd->resumestart) / sd->transtime;
  223.     if (sd->cps > 0)
  224.         sd->timeleft = (sd->size - sd->cur) / sd->cps;
  225.     else sd->timeleft = 0;
  226. }
  227.  
  228.  
  229. void TransferSetError(struct TransferData *data, char *title, char *user, int error)
  230. {
  231.     u_long tmp;
  232.     songtrans sd;
  233.     long i;
  234.  
  235.     for (i=0; ; i++) {
  236.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  237.         if (!tmp) return;
  238.         sd = (songtrans)tmp;
  239.         if (strcmp(sd->song->title, title) == 0 && stricmp(sd->song->user, user) == 0) break;
  240.     }
  241.  
  242.     if ((sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) && sd->state == DLS_PREP) {
  243.         DoMethod(gui->dwin, DL_COUNTDECREMENT);
  244.     }
  245.  
  246.     sd->state = DLS_ERROR;
  247.     sd->error = error;
  248.  
  249.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
  250.     else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  251. }
  252.  
  253.  
  254. void TransferInfo(struct TransferData *data)
  255. {
  256.     static char bufd[600], bufu[600];
  257.     char *buf;
  258.     u_long tmp;
  259.     songtrans sd;
  260.  
  261.     GetAttr(MUIA_NList_EntryClick,  data->list, &tmp);
  262.     if (tmp == -1 || tmp == -2) return;
  263.     DoMethod(data->list, MUIM_NList_GetEntry, tmp, &sd);
  264.     if (!sd) return;
  265.  
  266.     if (sd->song->ip == 0) return;
  267.  
  268.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) buf = bufd;
  269.     else buf = bufu;
  270.  
  271.     if (sd->host[0] == '\0') {
  272.         sprintf(buf, "%s (%d.%d.%d.%d)", sd->song->user, (sd->song->ip&0xFF000000)>>24, (sd->song->ip&0xFF0000)>>16, (sd->song->ip&0xFF00)>>8, sd->song->ip&0xFF);
  273.     }
  274.     else {
  275.         sprintf(buf, "%s (%s)", sd->song->user, sd->host);
  276.     }
  277.  
  278.     set(data->info, MUIA_Text_Contents, buf);
  279. }
  280.  
  281.  
  282. void TransferAbort(struct TransferData *data)
  283. {
  284.     u_long item;
  285.     songtrans sd;
  286.  
  287.     DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
  288.     if (!item) return;
  289.  
  290.     sd = (songtrans)item;
  291.  
  292.     if (sd->state >= DLS_FIN) {
  293.         return;
  294.     }
  295.  
  296.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  297.         if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
  298.         if (sd->state == DLS_QUEUE) QueueCount--;
  299.     }
  300.  
  301.     if (sd->t) {
  302.         th_message(sd->t, THC_EXIT, 0);
  303.         Signal(sd->t->task, SIGBREAKF_CTRL_C);
  304.     }
  305.     else {
  306.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  307.             if (sd->state != DLS_QUEUE) {
  308.                 DoMethod(gui->dwin, DL_COUNTDECREMENT);
  309.             }
  310.         }
  311.         else DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
  312.     }
  313.  
  314.     sd->state = DLS_ABORT;
  315.  
  316.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
  317.     else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  318. }
  319.  
  320.  
  321. void TransferCleanup(struct TransferData *data)
  322. {
  323.     u_long item;
  324.     int i=0, j;
  325.  
  326.     while (1) {
  327.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  328.         if (!item) break;
  329.         j = ((songtrans)item)->state;
  330.         if (j >= DLS_FIN) DoMethod(data->list, MUIM_NList_Remove, i);
  331.         else i++;
  332.     }
  333. }
  334.  
  335.  
  336. void TransferWatcher(struct TransferData *data)
  337. {
  338.     u_long item;
  339.     long i;
  340.     songtrans sd;
  341.  
  342.     for (i=0; ; i++) {
  343.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  344.         if (!item) break;
  345.         sd = (songtrans)item;
  346.         if (sd->state == DLS_PREP) {
  347.             if (time(NULL)-sd->reqtime > 120) {    /* We consider this transfer dead/hanging (never started) */
  348.                 sd->state = DLS_ERROR;
  349.                 sd->error = ERROR_TIMEOUT;
  350.                 if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  351.                     DoMethod(gui->dwin, DL_COUNTDECREMENT);
  352.                     DoMethod(gui->dwin, DL_UPDATE, sd);
  353.                 }
  354.                 else {
  355.                     DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
  356.                     DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  357.                 }
  358.             }
  359.         }
  360.     }
  361. }
  362.  
  363.  
  364. void TransferHandleError(songtrans sd)
  365. {
  366.     char error[128];
  367.  
  368.     if (sd->ErrorCode == EINTR) return;    /* Aborted with CTRL-C */
  369.  
  370.     if (sd->error != 0) {
  371.         sd->state = DLS_ERROR;
  372.         if (sd->error >= ERROR_FILEOPEN && sd->error <= ERROR_FILEWRITE) {
  373.             Fault(sd->ErrorCode, "", error, 127);
  374.             gui_debugf((char *)MSG_INFO_IOERROR, sd->fname, error);
  375.         }
  376.         else if (sd->error >= ERROR_OUTOFBOUND) sd->error = ERROR_UNKNOWN;
  377.         prf_event(PRFE_DLERROR);
  378.     }
  379.     else if (sd->state == DLS_FIN) {
  380.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) prf_event(PRFE_DLFINISH);
  381.         else prf_event(PRFE_ULFINISH);
  382.     }
  383.  
  384.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
  385.     else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  386. }
  387.  
  388.  
  389. /* Thread stuff */
  390.  
  391. BOOL InitTransferThread(thread t, songtrans sd)
  392. {
  393.     struct Library *DosBase;
  394.     struct Library *SocketBase;
  395.     char *buffer;
  396.     long s;
  397.     long tmp;
  398.     struct hostent *he;
  399.  
  400.     sd->state = DLS_PREP;
  401.  
  402.     sd->nsig = AllocSignal(-1);
  403.     if (sd->nsig == -1) {
  404.         ExitTransferThread(sd, 49);
  405.         return FALSE;
  406.     }
  407.     sd->nsigm = (1L << (sd->nsig));
  408.     sd->msigm = (1L << (t->port->mp_SigBit));
  409.  
  410.     DosBase = OpenLibrary("dos.library", 0);
  411.     if (!DosBase) {
  412.         ExitTransferThread(sd, 50);
  413.         return FALSE;
  414.     }
  415.     sd->DosBase = DosBase;
  416.  
  417.     SocketBase = OpenLibrary("bsdsocket.library", 0);
  418.     if (!SocketBase) {
  419.         ExitTransferThread(sd, 51);
  420.         return FALSE;
  421.     }
  422.     sd->SocketBase = SocketBase;
  423.  
  424.     SocketBaseTags(SBTM_SETVAL(SBTC_SIGIOMASK), (char *)sd->nsigm, TAG_DONE);
  425.  
  426.     buffer = malloc(8192);
  427.     if (!buffer) {
  428.         ExitTransferThread(sd, 52);
  429.         return FALSE;
  430.     }
  431.     sd->buffer = buffer;
  432.  
  433.     /* Perform DNS-lookup */
  434.     he = gethostbyname(Inet_NtoA(sd->song->ip));
  435.     he = gethostbyaddr(he->h_addr_list[0], he->h_length, AF_INET);
  436.     if (he != 0) strcpy(sd->host, he->h_name);
  437.     else strcpy(sd->host, Inet_NtoA(sd->song->ip));
  438.  
  439.     s = socket(AF_INET, SOCK_STREAM, 0);
  440.     if (s < 0) {
  441.         ExitTransferThread(sd, 53);
  442.         return FALSE;
  443.     }
  444.     sd->s = s;
  445.  
  446.     sd->sin.sin_addr.s_addr = sd->ip;
  447.     sd->sin.sin_port = htons(sd->port);
  448.     sd->sin.sin_family = AF_INET;
  449.     sd->sin.sin_len = sizeof(sd->sin);
  450.  
  451.     tmp = 1;
  452.     IoctlSocket(s, FIOASYNC, (char *)&tmp);
  453.     IoctlSocket(s, FIONBIO,  (char *)&tmp);
  454.     /* Asynchronous and non-blocking I/O to the socket */
  455.  
  456.     tmp = connect(s, (struct sockaddr *)&sd->sin, sizeof(sd->sin));
  457.     if (tmp == -1 && Errno() != EINPROGRESS) {
  458.         sd->ErrorCode = Errno();
  459.         ExitTransferThread(sd, ERROR_NET);
  460.         return FALSE;
  461.     }
  462.  
  463.     thr_message(t, DLC_STATE, (APTR)DLS_CON);
  464.  
  465.     return TRUE;
  466. }
  467.  
  468.  
  469. void ExitTransferThread(songtrans sd, int ret)
  470. {
  471.     struct Library *DosBase=sd->DosBase;
  472.     struct Library *SocketBase=sd->SocketBase;
  473.  
  474.     if (sd->nsig != -1) FreeSignal(sd->nsig);
  475.     sd->nsig = -1;
  476.  
  477.     if (sd->f) Close(sd->f);
  478.     sd->f = 0;
  479.  
  480.     if (sd->s != -1) CloseSocket(sd->s);
  481.     sd->s = -1;
  482.  
  483.     if (sd->buffer) free(sd->buffer);
  484.     sd->buffer = NULL;
  485.  
  486.     if (SocketBase) CloseLibrary(SocketBase);
  487.     sd->SocketBase = NULL;
  488.  
  489.     if (DosBase) CloseLibrary(DosBase);
  490.     sd->DosBase = NULL;
  491.  
  492.     thr_exit(sd->t, ret);
  493. }
  494.